package com.flyme.common.security.filter;

import com.flyme.common.security.model.UsernamePasswordToken;
import com.flyme.common.security.util.AuthenticationException;
import com.flyme.common.security.util.SecurityUtils;
import com.flyme.common.security.util.WebUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Base class for all Filters that require the current user to be authenticated.
 * <p>
 * Created by xinxingegeya on 2017/5/18.
 */
public abstract class AuthenticationFilter extends AbstractAccessControlFilter {

    public static final String GET_METHOD = "GET";
    public static final String POST_METHOD = "POST";

    public static final String DEFAULT_LOGIN_URL = "/login.jsp";
    public static final String DEFAULT_SUCCESS_URL = "/";

    private String loginUrl = DEFAULT_LOGIN_URL;
    private String successUrl = DEFAULT_SUCCESS_URL;

    /**
     * @return the success url to use as the default location a user is sent after logging in.
     */
    public String getSuccessUrl() {
        return successUrl;
    }

    /**
     * Sets the default/fallback success url to use as the default location a user is sent after logging in.
     *
     * @param successUrl the success URL to redirect the user to after a successful login.
     */
    public void setSuccessUrl(String successUrl) {
        this.successUrl = successUrl;
    }

    /**
     * Returns the login URL used to authenticate a user.
     *
     * @return the login URL used to authenticate a user, used when redirecting users if authentication is required.
     */
    public String getLoginUrl() {
        return loginUrl;
    }

    /**
     * Sets the login URL used to authenticate a user.
     *
     * @param loginUrl the login URL used to authenticate a user, used when redirecting users if authentication is required.
     */
    public void setLoginUrl(String loginUrl) {
        this.loginUrl = loginUrl;
    }

    /**
     * Returns <code>true</code> if the incoming request is a login request, <code>false</code> otherwise.
     *
     * @param request  the incoming <code>HttpServletRequest</code>
     * @param response the outgoing <code>HttpServletResponse</code>
     * @return <code>true</code> if the incoming request is a login request, <code>false</code> otherwise.
     */
    protected boolean isLoginRequest(HttpServletRequest request, HttpServletResponse response) {
        return pathsMatch(getLoginUrl(), request);
    }

    /**
     * This default implementation merely returns <code>true</code> if the request is an HTTP <code>POST</code>,
     * <code>false</code> otherwise.
     *
     * @param request
     * @param response
     * @return
     */
    protected boolean isLoginSubmission(HttpServletRequest request, HttpServletResponse response) {
        return WebUtils.toHttp(request).getMethod().equalsIgnoreCase(POST_METHOD);
    }

    /**
     * Convenience method for subclasses that merely acquires the {@link #getLoginUrl() getLoginUrl} and redirects
     * the request to that url.
     *
     * @param request  the incoming <code>HttpServletRequest</code>
     * @param response the outgoing <code>HttpServletResponse</code>
     * @throws IOException if an error occurs.
     */
    protected void redirectToLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String loginUrl = getLoginUrl();
        WebUtils.issueRedirect(request, response, loginUrl);
    }

    /**
     * Determines whether the current user is authenticated.
     *
     * @return true if the subject is authenticated; false if the subject is unauthenticated
     */
    @Override
    protected boolean isAccessAllowed(HttpServletRequest request, HttpServletResponse response) {
        return request.getSession().getAttribute(SecurityUtils.USER_SESSION_LOGIN_KEY) != null && (Boolean) request.getSession().getAttribute(SecurityUtils.USER_SESSION_LOGIN_KEY);
    }

    protected boolean onLoginSuccess(UsernamePasswordToken token,
                                     HttpServletRequest request, HttpServletResponse response) throws Exception {
        return true;
    }

    protected boolean onLoginFailure(UsernamePasswordToken token, AuthenticationException e,
                                     HttpServletRequest request, HttpServletResponse response) {
        return false;
    }

}
